今天要來寫登入的 API 串接,取得 JWT 後,存至 localStorage。
目前先用程式動態產生 key 的方式,之後有機會再來研究產生公私鑰。
動態產生 key 的話,在驗證 jwt 時,如果有將 container 容器重啟的話,那麼原來產生的 jwt 自然就會驗證不通過,因為 key 已經變了。
在 webmix_api 資料夾底下,建立 apiKey.ts 檔案,內容如下:
// 產生 key
export const key = await crypto.subtle.generateKey(
  { name: "HMAC", hash: "SHA-256" },
  true,
  ["sign", "verify"],
);
開啟 resolvers.ts 檔案,最上方加底下這行:
import { key } from "./apiKey.ts";
然後多一個函式如下,取得特定 email 的使用者:
async function getUser(email){
  return await client.query("SELECT * FROM users WHERE email = '" + email + "'");
}
然後原來的 authUser 函式,改寫如下,主要會有 密碼驗證的功能,以及若密碼驗證通過,那就產生 JWT 回傳:
async function authUser(args){
  let user_data = await getUser(args.username);
  //console.log(user_data[0].password);
  if(user_data.length > 0){
    // 解密
    const pwd_result = await bcrypt.compare(args.password, user_data[0].password);
    if(pwd_result){ // 密碼核對通過,回傳 JWT
      // 產生 jwt
      let jwt = await create({ alg: "HS256", typ: "JWT" }, {
        id: user_data[0].id,
        nickname: user_data[0].nickname,
        exp: getNumericDate(60 * 60)}, key
      );
      return jwt;
    }
  }
  return "false";
}
在 webmix_efficiency 資料夾下,src/views/Home.vue 檔案,在 script 標籤內,加上以下的程式:
這段程式,主要有幾個用途:
<script>
  export default {
    data(){
      return {
        email: "",
        password: ""
      };
    },
    methods: {
      auth_user(){
        fetch("http://localhost:8080/graphql", {
          method: 'POST',
          body: JSON.stringify({
            query: `mutation {
              authUser(username: "${this.email}", password: "${this.password}")
            }`
          })
        }).then(res => res.json()).then(data => {
          if(data.data !== null && data.data.authUser !== "false"){
            localStorage.setItem("jwt", data.data.authUser);
            alert("登入成功");
            location.reload();
          }else{
            alert("登入失敗");
          }
        });
      }
    }
  }
</script>
然而在 template 標籤內,以下這行:
input(type="text")
改成:
input(type="text" v-model="email")
以下這行:
input(type="password")
改成:
input(type="password" v-model="password")
以下這行:
button(type="button") 登入
改成:
button(type="button" @click="auth_user") 登入
改完後,就可以實際測試看看囉,在登入頁面,輸入帳、密,按下登入按鈕,成功的話,就會跳成功的 alert,然後頁面會重新整理,就可以看看 localStorage 是否有 JWT 喔,如下圖藍框處:

太好了,有存下來了。
存下 JWT 之後,後續就可以檢查目前使用者的登入狀態囉。倒數十天了!